# coding=utf-8
import json
import re
from django.conf import settings
from django_redis import get_redis_connection
from rest_framework.permissions import BasePermission
import logging
from MSB_ERP.utils.cache_permissions import redis_storage_permissions

logging.getLogger('erp')

class RbacPermission(BasePermission):

    def do_uri(self,url):
        '''把一个不完整的地址，变成一个完整的'''
        # /users/（不完整的） --> /api/users/（完整的）
        base_api = settings.BASE_API
        uri = '/' + base_api + '/' + url + '/'

        # sub意思是去重操作，'/+'表示有两个以上的斜线，全部替换成'/'一个斜线，最后传入参数
        return re.sub('/+','/',uri) # re.sub做去重

    ''' 自定义权限认证的判断 '''
    def has_permission(self, request, view):
        '''
        判断是否有权限，该函数必须要重写
        思路和步骤：
        1.获取请求的URL，和请求方法method，user用户对象
        2.判断是否是白名单的URL，或者用户是角色是admin（最高权限）也直接放行
        3.从redis中得到当前登录用户的所有权限
        4.判断是否存在权限
        '''

        # 获取请求地址
        request_url = request.path
        # 获取请求方法
        request_method = request.method
        # 输出日志（方便以后看看哪里有错）
        logging.info(f'请求地址为：{request_url},请求方法为：{request_method}')
        # 优先过滤白名单（settings拿到配置文件里面的内容，注意：导包时不能直接导文件的路径）
        # 这里导包的方法是：from django.conf import settings就可以拿到配置文件的内容了
        for safe_url in settings.WHITE_LIST:

            # re.match使用正则表达式来匹配字符串
            # settings.REGEX_URL.format(url=safe_url)白名单的正则表达式
            # request_url前端请求的url地址
            if re.match(settings.REGEX_URL.format(url=safe_url),request_url):

                # 用户请求的是白名单的url
                # has_permission这个重写的函数只要是返回True表示有权限的意思
                return True

        user = request.user # 当前登录的用户
        # 获得用户的所有角色
        role_name_list = user.roles.values_list('name',flat=True)
        if 'admin' in role_name_list:
            return True

        # 从redis中获取该用户的所有权限
        redis_conn = get_redis_connection('default') # redis数据库的连接
        if not redis_conn.exists(f'user_{user.id}'): # 如果redis没有缓存权限
            redis_storage_permissions(user) # 再从mysql中取出，并再一次缓存到redis数据库中

        # 得到所有的权限中的key，其中key是接口的url的地址
        url_keys = redis_conn.hkeys(f'user_{user.id}')
        redis_key = None
        for url_key in url_keys:

            # 注意：redis中存放的是字节数据 .decode()字节转化成字符串
            if re.match(settings.REGEX_URL.format(url=self.do_uri(url_key.decode())),request_url):
                # 如果redis中的uri和请求uri一致的
                redis_key = url_key.decode() # 接收参数，并转化成字符串
                break # 终止循环
        if redis_key:
            # 将json字符串转化成字典
            permissions = json.loads(redis_conn.hget(f'user_{user.id}',redis_key).decode())

            for permission in permissions:
                # 判断redis数据库中的method和请求过来的methd是不是一致的
                if permission.get('method') == request_method:
                    return True
        else:
            return False

